﻿package com.phantasy.scene.tile.gameAstar
{
	import com.phantasy.scene.tile.Pt;


    public class MCAstar 
    {

        private var _open:BinaryHeap;
        private var _grid:MapGrid;
        private var _endNode:Node;
        private var _startNode:Node;
        private var _path:Array;
        public var heuristic:Function;
        private var _straightCost:Number = 1;
        private var _diagCost:Number = 1.4142135623731;
        private var nowversion:int = 1;
        private var TwoOneTwoZero:Number;

        public function MCAstar(_arg1:MapGrid)
        {
            this.TwoOneTwoZero = (2 * Math.cos((Math.PI / 3)));
            super();
            this._grid = _arg1;
            this.heuristic = this.manhattan;
        }

        private function justMin(_arg1:Object, _arg2:Object):Boolean
        {
            return ((_arg1.f < _arg2.f));
        }

        public function findPath(_arg1:Pt, _arg2:Pt):Array
        {
            this._startNode = this._grid.getNode(_arg1.x, _arg1.z);
            this._endNode = this.checkNode(_arg2, 20);
            if ((((this._startNode == null)) || ((this._endNode == null))))
            {
                return (null);
            };
            this.nowversion++;
            this._open = new BinaryHeap(this.justMin);
            this._startNode.g = 0;
            var _local3:Boolean = this.search();
            if (_local3)
            {
                return (this.path);
            };
            return (null);
        }

        public function search():Boolean
        {
            var _local2:int;
            var _local3:int;
            var _local4:Node;
            var _local5:Number;
            var _local6:Number;
            var _local7:Number;
            var _local8:Number;
            var _local1:Node = this._startNode;
            this._grid.initNodeLink(this._startNode);
            _local1.version = this.nowversion;
            while (_local1 != this._endNode)
            {
                _local2 = _local1.links.length;
                _local3 = 0;
                while (_local3 < _local2)
                {
                    _local4 = _local1.links[_local3].node;
                    this._grid.initNodeLink(_local4);
                    if (!(((((_local4.walkable == false)) && (!((_local4 == this._endNode))))) && ((((Math.abs((_local4.x - this._startNode.x)) < 4)) && ((Math.abs((_local4.y - this._startNode.y)) < 4))))))
                    {
                        _local5 = _local1.links[_local3].cost;
                        _local6 = (_local1.g + _local5);
                        _local7 = this.heuristic(_local4);
                        _local8 = (_local6 + _local7);
                        if (_local4.version == this.nowversion)
                        {
                            if (_local4.f > _local8)
                            {
                                _local4.f = _local8;
                                _local4.g = _local6;
                                _local4.h = _local7;
                                _local4.parent = _local1;
                            };
                        }
                        else
                        {
                            _local4.f = _local8;
                            _local4.g = _local6;
                            _local4.h = _local7;
                            _local4.parent = _local1;
                            this._open.ins(_local4);
                            _local4.version = this.nowversion;
                        };
                    };
                    _local3++;
                };
                if (this._open.a.length == 1)
                {
                    return (false);
                };
                _local1 = (this._open.pop() as Node);
            };
            this.buildPath();
            return (true);
        }

        private function buildPath():void
        {
            this._path = [];
            var _local1:Node = this._endNode;
            this._path.push(_local1.pt);
            while (_local1 != this._startNode)
            {
                _local1 = _local1.parent;
                this._path.unshift(_local1.pt);
            };
        }

        public function get path():Array
        {
            return (this._path);
        }

        private function checkNode(_arg1:Pt, _arg2:int):Node
        {
            var _local4:int;
            var _local5:Array;
            var _local3:Node = this._grid.getNode(_arg1.x, _arg1.z);
            if (_local3)
            {
                return (_local3);
            };
            _local4 = 1;
            while (_local4 <= _arg2)
            {
                _local5 = this.getOutLine(_arg1, _local4);
                if (_local5.length > 0)
                {
                    return (_local5[0]);
                };
                _local4++;
            };
            return (null);
        }

        private function getOutLine(_arg1:Pt, _arg2:int=1):Array
        {
            var _local5:int;
            var _local6:Node;
            var _local7:int;
            var _local8:int;
            var _local3:Array = [];
            var _local4:int = (_arg1.x - _arg2);
            while (_local4 <= (_arg1.x + _arg2))
            {
                _local5 = (_arg1.z - _arg2);
                while (_local5 <= (_arg1.z + _arg2))
                {
                    _local6 = this._grid.getNode(_local4, _local5);
                    if (_local6)
                    {
                        _local7 = Math.abs((_local6.x - _arg1.x));
                        _local8 = Math.abs((_local6.y - _arg1.z));
                        if ((((_local7 == _arg2)) || ((_local8 == _arg2))))
                        {
                            _local3.push(_local6);
                        };
                    };
                    _local5++;
                };
                _local4++;
            };
            return (_local3);
        }

        public function manhattan(_arg1:Node):Number
        {
            return (Math.max((Math.abs((_arg1.x - this._endNode.x)) + Math.abs((_arg1.y - this._endNode.y)))));
        }

        public function manhattan2(_arg1:Node):Number
        {
            var _local2:Number = Math.abs((_arg1.x - this._endNode.x));
            var _local3:Number = Math.abs((_arg1.y - this._endNode.y));
            return (((_local2 + _local3) + (Math.abs((_local2 - _local3)) / 1000)));
        }

        public function euclidian(_arg1:Node):Number
        {
            var _local2:Number = (_arg1.x - this._endNode.x);
            var _local3:Number = (_arg1.y - this._endNode.y);
            return (Math.sqrt(((_local2 * _local2) + (_local3 * _local3))));
        }

        public function chineseCheckersEuclidian2(_arg1:Node):Number
        {
            var _local2:int = (_arg1.y / this.TwoOneTwoZero);
            var _local3:int = (_arg1.x + (_arg1.y / 2));
            var _local4:Number = ((_local3 - this._endNode.x) - (this._endNode.y / 2));
            var _local5:Number = (_local2 - (this._endNode.y / this.TwoOneTwoZero));
            return (this.sqrt(((_local4 * _local4) + (_local5 * _local5))));
        }

        private function sqrt(_arg1:Number):Number
        {
            return (Math.sqrt(_arg1));
        }

        public function euclidian2(_arg1:Node):Number
        {
            var _local2:Number = (_arg1.x - this._endNode.x);
            var _local3:Number = (_arg1.y - this._endNode.y);
            return (((_local2 * _local2) + (_local3 * _local3)));
        }

        public function diagonal(_arg1:Node):Number
        {
            var _local2:Number = Math.abs((_arg1.x - this._endNode.x));
            var _local3:Number = Math.abs((_arg1.y - this._endNode.y));
            var _local4:Number = Math.min(_local2, _local3);
            var _local5:Number = (_local2 + _local3);
            return (((this._diagCost * _local4) + (this._straightCost * (_local5 - (2 * _local4)))));
        }


    }
}//package com.scene.tile.gameAstar
